package com.gress.shop.service.impl;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.gress.shop.bo.Menu;
import com.gress.shop.bo.example.MenuExample;
import com.gress.shop.dao.IActionDao;
import com.gress.shop.dao.IMenuDao;
import com.gress.shop.enums.MenuEnum;
import com.gress.shop.service.IActionService;
import com.gress.shop.service.IMenuService;
import com.gress.shop.util.HappyException;
import com.gress.shop.util.MyMenuComparator;
import com.gress.shop.vo.JsonId;
import com.gress.shop.vo.SwalFactory;
import com.gress.shop.vo.SwalReturn;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;

/**
 * Created xiongwen with 2018/3/6 15:56
 * Description:
 */
@Service
public class MenuService implements IMenuService {

    @Resource
    private IMenuDao menuDao;
    @Resource
    private IActionService actionService;

    @Override
    public Menu update(Menu menu) {
        return menuDao.update(menu);
    }

    @Override
    public Menu save(Menu menu) {
        checkSaveMenuParam(menu);
        return menuDao.save(menu);
    }

    private void checkSaveMenuParam(Menu menu) {
        String parentId = menu.getParentId();
        if (StringUtils.isEmpty(parentId)) {
            throw new HappyException("父级坐标为空");
        }
        if (StringUtils.isEmpty(menu.getName())) {
            throw new HappyException("名称不能为空");
        }
        // 不同类型菜单处理
        String type = menu.getType();
        if (!MenuEnum.checkLawful(type)) {
            throw new HappyException("类型不正确 ," + type);
        }
        if (org.apache.commons.lang.StringUtils.equals(MenuEnum.MENU.getMenuCode(),type)) {
            menu.setActionId(null);
            menu.setClickUrl(null);
        }else {
            if (StringUtils.isEmpty(menu.getClickUrl())) {
                throw new HappyException("功能跳转URL 为空" );
            }
            if (!actionService.checkIsExist(menu.getActionId())) {
                throw new HappyException("权限为空" );
            }
        }

        // 处理sortCode
        Menu parentMenu = menuDao.selectMenuById(parentId);
        if (null == parentMenu) {
            throw new HappyException("父级坐标已失效" );
        }
        if (!org.apache.commons.lang.StringUtils.equals(MenuEnum.MENU.getMenuCode(), parentMenu.getType())) {
            throw new HappyException("父级坐标不合法,不是一个菜单类型");
        }
        List<Menu> menus = menuDao.queryChildrenByParentId(parentId);
        if (CollectionUtils.isEmpty(menus)) {
            menu.setSortCode(0);
        }else {
            int sortCode = menus.get(0).getSortCode() + 1;
            menu.setSortCode(sortCode);
        }
    }

    @Override
    public SwalReturn deleteById(String id) {
        List<Menu> children = menuDao.queryChildrenByParentId(id);
        if (!CollectionUtils.isEmpty(children)) {
            throw new HappyException("存在子集菜单, 请先移除子集在做删除");
        }
        int i = menuDao.deleteById(id);
        if (i == 1) {
            return SwalFactory.getSuccessSwal();
        }else {
            return SwalFactory.getErrorSwal("删除失败");
        }
    }

    @Override
    public Menu selectMenuById(String id) {
        return menuDao.selectMenuById(id);
    }

    @Override
    public List<Menu> queryByExample(MenuExample example) {
        return menuDao.queryByExample(example);
    }

    @Override
    public Menu queryMenuById(String id) {
        return menuDao.selectMenuById(id);
    }


    @Override
    public Set<Menu> buildMenuTree(String email) {
        List<String> menuIdList = getMenuIdByEmail(email);
        List<Menu> menuList = menuDao.selectMenuByIds(menuIdList);
        return buildList(menuList);
    }

    /**
     * 拿出符合这个邮箱的所有功能包括菜单项
     */
    private List<String> getMenuIdByEmail(String email) {
        List<Menu> menus = menuDao.queryIsNotMenu();
        List<String> actionIdList = actionService.queryActionByEmail(email);
        Set<String> menuIdList = Sets.newHashSet();
        menus.forEach(e -> {
            String actionId = e.getActionId();
            if (StringUtils.isEmpty(actionId) || actionIdList.contains(actionId)) {
                menuIdList.add(e.getId());
                getIds(menuIdList, e.getId());
                return;
            }
        });
        return Lists.newArrayList(menuIdList);
    }

    private void getIds(Set<String> set, String id) {
        Menu menu = menuDao.selectMenuById(id);
        if (menu != null && !StringUtils.isEmpty(menu.getParentId())) {
            String parentId = menu.getParentId();
            set.add(parentId);
            getIds(set, parentId);
        }
    }

    @Override
    public Set<Menu> buildMenuTree() {
        List<Menu> menuList = menuDao.queryBLawfulMenu();
        return buildList(menuList);
    }

    /**
     * @param menuList
     * @Date: 14:23 2018/3/7
     * @Description: 时间复杂度低，用空间换时间
     **/
    private Set<Menu> buildList(List<Menu> menuList) {
        Map<String, Set<Menu>> map = new HashMap<>();
        Map<String, Menu> mapSingle = new HashMap<>();

        menuList.forEach(e -> {
            mapSingle.put(e.getId(), e);
            String parentId = e.getParentId();
            Set<Menu> menus = map.get(parentId);
            if (CollectionUtils.isEmpty(menus)) {
                menus = new TreeSet<>(new MyMenuComparator());
                map.put(parentId, menus);
                menus.add(e);
            } else {
                menus.add(e);
            }
        });

        Set<String> parentIdList = map.keySet();
        parentIdList.forEach(e -> {
            Menu menu = mapSingle.get(e);
            if (menu != null) {
                menu.setChildren(map.get(e));
            }
        });
        return map.get("0");
    }


    /**
     * @param menuList
     * @param parentId
     * @Date: 10:49 2018/3/7
     * @Description: 时间复杂度极高 ，用时间换空间
     **/
    private Set<Menu> buildList(List<Menu> menuList, String parentId) {
        Set<Menu> set = new TreeSet<>(new MyMenuComparator());
        for (Menu module : menuList) {
            if (module.getParentId().equals(parentId)) {
                set.add(module);
                module.setChildren(buildList(menuList, module.getId()));
            }
        }
        return set;
    }

    @Override
    @Transactional
    public void sortMenu(List<JsonId> jsonIds, String parentId) {
        if (CollectionUtils.isEmpty(jsonIds)) {
           return;
        }
        for (int i = 0; i < jsonIds.size(); i++) {
            JsonId jsonId = jsonIds.get(i);
            checkIsPermission(jsonId.getId(), parentId, jsonId.getChildren());
            Menu permission = new Menu();
            permission.setId(jsonId.getId());
            permission.setSortCode(i + 1);
            permission.setParentId(parentId);
            menuDao.saveSortCode(permission);
            sortMenu(jsonId.getChildren(), jsonId.getId());
        }
    }
    private void checkIsPermission(String id, String parentId, List<JsonId> children) {
        Menu sysPermissionDo = queryMenuById(id);
        if (null == sysPermissionDo) {
            // 不能找到相关对象
            throw new HappyException("系统异常");
        }
        if (CollectionUtils.isEmpty(children)) {
        }else {
            //校验权限下不能有子集
            if (sysPermissionDo == null || !"menu".equals(sysPermissionDo.getType())) {
                throw new HappyException("权限下面不能包含子集");
            }
        }
    }
}
